package com.google.code.guava.base;

/**
 * Helper class for generating {@link RuntimeException RuntimeExceptions} from
 * incoming Exceptions.
 */
public final class Exceptions{

    /**
     * Default message for generated {@link RuntimeException RuntimeExceptions}.<br />
     * Value: {@value}
     */
    public static final String DEFAULT_MESSAGE = "Unknown Error";

    /**
     * Creates a {@link RuntimeException} with a message built using
     * {@link String#format(String, Object...)}.
     * 
     * @param message
     *            the message template
     * @param params
     *            the template parameters
     * @return a RuntimeException
     */
    public static RuntimeException create(final String message,
        final Object ... params){
        return createRuntimeException(null, message, params);
    }

    static RuntimeException createRuntimeException(final Exception e,
        final String message, final Object ... parameters){
        final String expMessage;
        if(message != null){
            expMessage = String.format(message, parameters);
        }else if(e != null){
            expMessage = findMessageInExceptionTree(e);
        }else{
            expMessage = Exceptions.DEFAULT_MESSAGE;
        }
        return new IllegalStateException(expMessage, e);
    }

    private static String findMessageInExceptionTree(final Exception e){
        Throwable current = e;
        while(current.getMessage() == null){
            if(current.getCause() == null){
                break;
            }else{
                if(current.getCause() == current){
                    // sanity check
                    break;
                }
                current = current.getCause();
            }

        }
        return current.getMessage() == null
        ? Exceptions.DEFAULT_MESSAGE
        : current.getMessage();
    }

    /**
     * Create a {@link RuntimeException} that wraps the supplied exception. The
     * exception's message will be the first non-null message found in the
     * exception hierarchy of the supplied exception, or
     * {@link #DEFAULT_MESSAGE} if no such message can be found.
     */
    public static RuntimeException rethrow(final Exception exp){
        return rethrow(exp, null);
    }

    /**
     * Create a {@link RuntimeException} that wraps the supplied exception. The
     * exception's message will be created by applying
     * {@link String#format(String, Object...)} on the <code>message</code>
     * parameter and the optional supplied parameters, if <code>message</code>
     * is not null. If the <code>message</code> parameter is null, the first
     * non-null message found in the exception hierarchy of the supplied
     * exception will be used, or {@link #DEFAULT_MESSAGE} if no such message
     * can be found.
     */
    public static RuntimeException rethrow(final Exception e,
        final String message, final Object ... parameters){
        return createRuntimeException(e, message, parameters);
    }

    private Exceptions(){}

}
